#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>

enum PrintBehavior {
    CloseAtSameLine,
    CloseAtOtherLine
};

/* Constant Declarations */
char Look;// Lookahead Character
const int buf_len = 64;
int DLevel = 0; // Debug log level

/* Print Token. Usage: PrintEnter(Token, CloseAtOtherLine/CloseAtSameLine).
   If CloseAtOtherLine, when going out of the Token name scope, you must call PrintLeave().
 */
void PrintEnter(const char* s, PrintBehavior behavior = CloseAtOtherLine) {
    for (int i = 0; i < DLevel; ++i) {
        printf("\t");
    }
    printf("<%s", s);
    if (behavior == CloseAtSameLine) {
        printf(">\n");
    }
    else {
        printf("\n");
        ++DLevel;
    }
}

void PrintLeave() {
    for (int i = 1; i < DLevel; ++i) {
        printf("\t", DLevel);
    }
    printf(">\n");
    --DLevel;
}
    

/* Read New Character From Input Stream */
void GetChar() {
  Look = getchar();
}

/* Report an Error */
void WriteLn(const char* s) {
  if (s) {
	printf(s);
  }

  printf("\n");
}

void Error(const char* s) {
  WriteLn(0);

  char buf[buf_len] = {0};
  sprintf(buf, "Error: %s.", s);
  WriteLn(buf);
}

/* Report Error and Halt */
void Abort(const char* s) {
  Error(s);
  exit(0);
}

/* Report What Was Expected */
void Expected(const char* s) {
  char buf[buf_len] = {0};
  sprintf(buf, "%s Expected", s);
  Abort(buf);
}

/* Forward Declarations */
void EmitLn(const char* s);
void BoolTerm();
void Expression();

/* Match a Specific Input Character */
void Match(char x) {
  if (Look == x) {
	GetChar();
  }
  else {
	char buf[buf_len] = {0};
	sprintf(buf, "'''' %c ''''", x);
	Expected(buf);
  }
}

/* Recognize an Alpha Character  */
int IsAlpha(char c) {
  return isalpha(c);
}

/* Recognize a Decimal Digit */
int IsDigit(char c) {
  return isdigit(c);
}

/* Recognize an Addop */
int IsAddop(char c) {
  if ((c == '+') ||
	  (c == '-')) {
	return 1;
  }
  else {
	return 0;
  }
}

/* Recognize a Boolean Orop */
int IsOrop(char c) {
    return (c == '|') || (c == '~');
}

/* Recognize a Relop */
int IsRelop(char c) {
    switch (c) {
    case '=':
    case '#':
    case '<':
    case '>':
        return 1;
    default:
        return 0;
    }
}

/* Recognize a Boolean Literal */
int IsBoolean(char c) {
    switch(toupper(c)) {
    case 'T':
    case 'F':
        return 1;
    default:
        return 0;
    }
}

/* Get a Boolean Literal */
int GetBoolean() {
    if (!IsBoolean(Look)) {
        Expected("Boolean Literal");
    }

    int result = (toupper(Look) == 'T');
    GetChar();

    PrintEnter("BoolLiteral", CloseAtSameLine);
    return result;
}

/* Get an Identifier */
char GetName() {
  if (!IsAlpha(Look)) {
	Expected("Name");
  }

  char result = Look;
  GetChar();

  PrintEnter("NAME", CloseAtSameLine);
  return result;
}

/* Parse and Translate an Identifier */
void Ident() {
    PrintEnter("Ident");
    
    if (Look == '(') {
        PrintEnter("FUNC", CloseAtSameLine);

        Match('(');
        Match(')');

        char buf[buf_len] = {0};
        sprintf(buf, "BSR %c", GetName());
        /* EmitLn(buf); */
    }
    else {
        PrintEnter("NotFUNC", CloseAtSameLine);
        
        char buf[buf_len] = {0};
        sprintf(buf, "MOVE %c(PC),D0", GetName());
        /* EmitLn(buf); */
    }

    PrintLeave();
}

/* Get a Number */
char GetNum() {
  if (!IsDigit(Look)) {
	Expected("Integer");
  }

  char result = Look;
  GetChar();

  PrintEnter("NUMBER", CloseAtSameLine);
  return result;
}

/* Parse and Translate a Math Factor */
void Factor() {
    PrintEnter("Factor");
    
    if (Look == '(') {
        Match('(');
        Expression();
        Match(')');
    }
    else if (IsAlpha(Look)) {
        Ident();
    }
    else {
        char buf[buf_len] = {0};
        sprintf(buf, "MOVE #%c,D0", GetNum());
        /* EmitLn(buf); */
    }

    PrintLeave();
}

/* Parse and Translate the First Math Factor */
void SignedFactor() {
    PrintEnter("SignedFactor");
    
    if (Look == '+') {
        PrintEnter("Sign+", CloseAtSameLine);

        GetChar();
    }

    if (Look == '-') {
        PrintEnter("Sign-", CloseAtSameLine);
        
        GetChar();
        if (IsDigit(Look)) {
            char buf[buf_len] = {0};
            sprintf(buf, "MOVE #-%c,D0", GetNum());
            /* EmitLn(buf); */
        }
        else {
            Factor();
            /* EmitLn("NEG D0"); */
        }
    }
    else {
        Factor();
    }

    PrintLeave();
}

/* Recognize and Translate a Multiply */
void Multiply() {
    PrintEnter("Multiply", CloseAtSameLine);

    Match('*');
    Factor();
    /* EmitLn("MULS (SP)+,D0"); */
}

/* Recognize and Translate a Divide */
void Divide() {
    PrintEnter("Divide", CloseAtSameLine);
    
    Match('/');
    Factor();
    /* EmitLn("MOVE (SP)+,D1"); */
    /* EmitLn("EXS.L D0"); */
    /* EmitLn("DIVS D1,D0"); */
}

/* Parse and Translate a Math Term */
void Term() {
    PrintEnter("Term");

    SignedFactor();
    while ((Look == '*') || (Look == '/')) {
        /* EmitLn("MOVE D0,-(SP)"); */
        switch (Look) {
        case '*': {
            Multiply();
            break;
        }
        case '/': {
            Divide();
            break;
        }
        }
    }
    
    PrintLeave();
}

/* Recognize and Translate an Add */
void Add() {
    PrintEnter("Add", CloseAtSameLine);

    Match('+');
    Term();
    /* EmitLn("ADD (SP)+,D0"); */
}

/* Recognize and Translate a Subtract */
void Subtract() {
    PrintEnter("Sub", CloseAtSameLine);
    
    Match('-');
    Term();
    /* EmitLn("SUB (SP)+,D0"); */
    /* EmitLn("NEG D0"); */
}

/* Parse and Translate an Expression */
void Expression() {
    PrintEnter("Expression");
    
    Term();
    while (IsAddop(Look)) {
        /* EmitLn("MOVE D0,-(SP)"); */
        switch (Look) {
        case '+': {
            Add();
            break;
        }
        case '-': {
            Subtract();
            break;
        }
        }
    }

    PrintLeave();
}

/* Recognize and Translate a Relational "Equals" */
void Equals() {
    PrintEnter("Equals", CloseAtSameLine);
    
    Match('=');
    Expression();
    /* EmitLn("CMP (SP)+,D0"); */
    /* EmitLn("SEQ D0"); */
}

/* Recognize and Translate a Relational "Not Equals" */
void NotEquals() {
    PrintEnter("Not Equals", CloseAtSameLine);
    
    Match('#');
    Expression();
    /* EmitLn("CMP (SP)+,D0"); */
    /* EmitLn("SNE D0"); */
}

/* Recognize and Translate a Relational "Less Than" */
void Less() {
    PrintEnter("Less", CloseAtSameLine);
    
    Match('<');
    Expression();
    /* EmitLn("CMP (SP)+,D0"); */
    /* EmitLn("SGE D0"); */
}

/* Recognize and Translate a Relational "Greater Than" */
void Greater() {
    PrintEnter("Greater", CloseAtSameLine);
    
    Match('>');
    Expression();
    /* EmitLn("CMP (SP)+,D0"); */
    /* EmitLn("SLE D0"); */
}

/* Parse and Translate a Relation */
void Relation() {
    PrintEnter("Relation");
    
    Expression();
    if (IsRelop(Look)) {
        /* EmitLn("MOVE D0,-(SP)"); */
        switch (Look) {
        case '=':
            Equals();
            break;
        case '#':
            NotEquals();
            break;
        case '<':
            Less();
            break;
        case '>':
            Greater();
            break;
        }
        /* EmitLn("TST D0"); */
    }
    
    PrintLeave();
}

/* Recognize and Translate a Boolean OR */
void BoolOr() {
    PrintEnter("OROP::Or", CloseAtSameLine);

    Match('|');
    BoolTerm();
    /* EmitLn("OR (SP)+,D0"); */
}

/* Recognize and Translate an Exclusive OR */
void BoolXor() {
    PrintEnter("OROP::Xor", CloseAtSameLine);

    Match('~');
    BoolTerm();
    /* EmitLn("EOR (SP)+,D0"); */
}

/* Parse and Translate a Boolean Factor */
void BoolFactor() {
    PrintEnter("BoolFactor");
    
    if (IsBoolean(Look)) {
        if (GetBoolean()) {
            /* EmitLn("MOVE #-1,D0"); */
        }
        else {
            /* EmitLn("CLR D0"); */
        }
    }
    else {
        Relation();
    }

    PrintLeave();
}

/* Parse and Translate a Boolean Factor with NOT */
void NotFactor() {
    PrintEnter("NotFactor");
    
    if (Look == '!') {
        PrintEnter("NOT", CloseAtSameLine);
        
        Match('!');
        BoolFactor();
        /* EmitLn("EOR #-1,D0"); */
    }
    else {
        BoolFactor();
    }

    PrintLeave();
}

/* Parse and Translate a Boolean Term */
void BoolTerm() {
    PrintEnter("BoolTerm");
    
    NotFactor();
    while (Look == '&') {
        PrintEnter("AND", CloseAtSameLine);
        
        /* EmitLn("MOVE D0,-(SP)"); */
        Match('&');
        NotFactor();
        /* EmitLn("AND (SP)+,D0"); */
    }

    PrintLeave();
}

/* Parse and Translate a Boolean Expression */
void BoolExpression() {
    PrintEnter("BoolExpression");
    
    BoolTerm();
    while (IsOrop(Look)) {
        /* EmitLn("MOVE D0,-(SP)"); */
        switch (Look) {
        case '|': {
            BoolOr();
            break;
        }
        case '~': {
            BoolXor();
            break;
        }
        }
    }

    PrintLeave();
}

/* Output a String with Tab */
void EmitLn(const char* s) {
  printf("\t %s\n", s);
}

/* Initialize */
void Init() {
  GetChar();
}

/* Main Program */
int main(int argc, char** argv) {
  Init();

  BoolExpression();
  return 0;
}

